package org.hawk.gwt.ppc.reflect;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.hawk.gwt.ppc.Configuration;
import org.hawk.gwt.ppc.GWTModule;
import org.hawk.gwt.ppc.ProcessingUnitsManager;
import org.hawk.gwt.ppc.introspection.SourcesRepository;
import org.hawk.gwt.ppc.loader.ProcessingUnit;
import org.hawk.gwt.ppc.parser.CompilationUnitDescriptor;
import org.hawk.gwt.ppc.parser.JavaKeywords;
import org.hawk.gwt.ppc.parser.Token;
import org.hawk.gwt.ppc.reflect.lang.ReflectAccessor;
import org.hawk.gwt.ppc.utils.PreprocessorException;

/**
 * Represents simple preprocessor to replace the package declaration for
 * <code>org.hawk.gwt.ppc.reflect.emul.java.lang</code> package classes. This
 * was done to retain the ability to run simple JUnit tests on java code.
 * 
 * @author alex.bereznevatiy@gmail.com
 */
public class LangPreprocessor implements ProcessingUnit {
	private static final String PACKAGE = "org.hawk.gwt.ppc.reflect";
	
	private static final Set<String> EXCLUDED_CLASSES = Collections.unmodifiableSet(
			new HashSet<String>(Arrays.asList(
					ReflectAccessor.class.getName()
			)));
	
	private SourcesRepository repository;

	/*
	 * (non-Javadoc)
	 * @see org.hawk.gwt.ppc.loader.ProcessingUnit#configure(org.hawk.gwt.ppc.Configuration, org.hawk.gwt.ppc.ProcessingUnitsManager)
	 */
	public void configure(Configuration config, ProcessingUnitsManager manager) {
		this.repository = manager.getRepository();
	}

	/*
	 * (non-Javadoc)
	 * @see org.hawk.gwt.ppc.loader.ProcessingUnit#processModule(org.hawk.gwt.ppc.GWTModule)
	 */
	public void processModule(GWTModule module) throws PreprocessorException {
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.hawk.gwt.ppc.loader.ProcessingUnit#processEntryPoint(java.lang.String)
	 */
	public void processEntryPoint(String entryPoint)
			throws PreprocessorException {
	}

	/*
	 * (non-Javadoc)
	 * @see org.hawk.gwt.ppc.loader.ProcessingUnit#acceptResource(java.lang.String)
	 */
	public boolean acceptResource(String resource) {
		return resource.startsWith(PACKAGE);
	}

	/*
	 * (non-Javadoc)
	 * @see org.hawk.gwt.ppc.loader.ProcessingUnit#processCompilationUnit(java.lang.String)
	 */
	public void processCompilationUnit(String compilationUnit)
			throws PreprocessorException {
		
		CompilationUnitDescriptor unit = repository.findCompilationUnit(compilationUnit);
		Token tok = unit.getPackage().getFirstToken();
		repository.markChanged(compilationUnit);
		if (EXCLUDED_CLASSES.contains(compilationUnit)) {
			eraseDefinitions(tok);
			return;
		}
		processLangPackage(tok);
		if (unit.getImports() == null) {
			return;
		}
		tok = unit.getImports().getFirstToken();
		while (tok != null && tok.equalsTo(JavaKeywords.IMPORT)) {
			tok = processLangPackage(tok);
		}
	}
	
	private Token processLangPackage(Token token) {
		Token iterator = token.next();
		Token flag = null;
		while (!iterator.equalsTo(';')) {
			if (iterator.equalsTo("emul")) {
				flag = iterator;
			}
			iterator = iterator.next();
		}
		if (flag == null) {
			return iterator.next();
		}
		
		token.getRaw().append(' ');
		
		flag = flag.next().next();
		
		while ((token = token.next()) != flag) {
			token.getRaw().setLength(0);
		}
		return iterator.next();
	}
	
	private void eraseDefinitions(Token token) {
		while (!(token = token.next()).equalsTo(';'));
		while ((token = token.next()) != null) {
			token.getRaw().setLength(0);
		}
	}
}
